﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Management;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;

namespace SimpleSlideShow
{
	public partial class Window1 : Window
	{
		private delegate void DisplayImageDelegate(string imageName);
		private Timer timer;
		private List<string> ImageList;

		WqlEventQuery query;
		ManagementEventWatcher watch;

		public Window1()
		{
			InitializeComponent();

			query = new WqlEventQuery("SELECT * FROM __InstanceOperationEvent WITHIN 10 WHERE TargetInstance ISA \"Win32_DiskDrive\"");
			watch = new ManagementEventWatcher(query);
			watch.EventArrived += new EventArrivedEventHandler(watch_EventArrived);
			watch.Start();
		}

		void watch_EventArrived(object sender, EventArrivedEventArgs e)
		{
			ManagementBaseObject mbo = e.NewEvent as ManagementBaseObject;
			ManagementBaseObject obj = mbo["TargetInstance"] as ManagementBaseObject;

			switch (mbo.ClassPath.ClassName)
			{
				case "__InstanceCreationEvent":
					if (obj["InterfaceType"].ToString() == "USB")
					{
						System.Diagnostics.Debug.Print("{0} has been plugged in.", obj["Caption"].ToString());
						LoadImages(true);
					}
					break;

				case "__InstanceDeletionEvent":
					if (obj["InterfaceType"].ToString() == "USB")
					{
						System.Diagnostics.Debug.Print("{0} has been unplugged.", obj["Caption"].ToString());
						SetLoadingTextVisibility(Visibility.Collapsed);
					}
					break;
			}
		}

		protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
		{
			watch.Stop();
			base.OnClosing(e);
		}

		private delegate void SetLoadingTextVisibilityDelegate(Visibility v);
		private delegate void SetImagesVisibilityDelegate(Visibility v);

		private void SetLoadingTextVisibility(Visibility v)
		{
			if (Dispatcher.Thread == Thread.CurrentThread)
				LoadingText.Visibility = v;
			else
				Dispatcher.Invoke(new SetLoadingTextVisibilityDelegate(SetLoadingTextVisibility), v);
		}

		private void SetImagesVisibility(Visibility v)
		{
			if (Dispatcher.Thread == Thread.CurrentThread)
			{
				MyImage1.Visibility = v;
				MyImage2.Visibility = v;
			}
			else
				Dispatcher.Invoke(new SetImagesVisibilityDelegate(SetImagesVisibility), v);
		}

		private void LoadImages(bool driveInserted)
		{
			SetLoadingTextVisibility(Visibility.Visible);
			timer.Change(Timeout.Infinite, 10000);

			ImageList = new List<string>();

			string path = Path.GetTempPath() + @"SimpleSlideShow\";
			DirectoryInfo di = new DirectoryInfo(path);

			if (driveInserted)
			{
				// Clear temp dir if it exists
				if (di.Exists)
				{
					foreach (var x in di.GetFiles())
					{
						try
						{
							x.Delete();
						}
						catch (Exception ex)
						{
							System.Diagnostics.Debug.Print(ex.Message);
						}
					}
				}
				di.Create();

				ManagementObjectSearcher mosDisks = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive WHERE InterfaceType = \"USB\"");

				// Loop through each object (disk) retrieved by WMI

				foreach (ManagementObject moDisk in mosDisks.Get())
				{
					foreach (ManagementObject b in moDisk.GetRelated("Win32_DiskPartition"))
					{
						foreach (ManagementObject c in b.GetRelated("Win32_LogicalDisk"))
						{
							DirectoryInfo dir = new DirectoryInfo(c["Name"].ToString());
							FileInfo[] f = dir.GetFiles("*.jpg", SearchOption.TopDirectoryOnly);
							foreach (var file in f)
							{
								if (IsValidImage(file.FullName))
								{
									File.Copy(file.FullName, path + file.Name);
									ImageList.Add(path + file.Name);
								}
							}
						}
					}
				}
			}
			else
			{
				if (di.Exists)
				{
					foreach (var file in di.GetFiles("*.jpg"))
						ImageList.Add(file.FullName);
				}
			}

			SetLoadingTextVisibility(Visibility.Collapsed);

			if (ImageList.Count > 0)
			{
				SetImagesVisibility(Visibility.Visible);
				timer.Change(0, 10000);
			}
			else
				SetImagesVisibility(Visibility.Collapsed);
		}

		bool IsValidImage(string filename)
		{
			try
			{
				BitmapImage newImage = new BitmapImage(new Uri(filename));
			}
			catch (NotSupportedException)
			{
				// System.NotSupportedException:
				// No imaging component suitable to complete this operation was found.
				return false;
			}
			return true;
		}

		private void Window_Loaded(object sender, RoutedEventArgs e)
		{
			timer = new Timer(new TimerCallback(onTimer), null, Timeout.Infinite, 10000);
			ImageList = new List<string>();

			LoadImages(false);
		}

		static int idx = 0;
		static bool useTop = false;

		private void onTimer(object state)
		{
			string nextImage = ImageList[idx];
			++idx;
			if (idx == ImageList.Count)
				idx = 0;

			DisplayImage(nextImage);
		}

		void DisplayImage(string imageName)
		{
			if (Thread.CurrentThread == App.Current.Dispatcher.Thread)
			{
				BitmapImage bitmapImage = new BitmapImage();

				bitmapImage.BeginInit();

				Stream s = new FileStream(imageName, FileMode.Open, FileAccess.Read);
				bitmapImage.StreamSource = s;

				bitmapImage.CacheOption = BitmapCacheOption.OnLoad;

				bitmapImage.EndInit();

				s.Close();
				
				if (useTop)
				{
					MyImage1.Source = bitmapImage;
					MyImage2.Opacity = 1.0;
					useTop = false;

					DoubleAnimation a = new DoubleAnimation(0.0, 1.0, new Duration(new TimeSpan(0, 0, 2)));
					MyImage1.BeginAnimation(Image.OpacityProperty, a);
				}
				else
				{
					MyImage2.Source = bitmapImage;
					MyImage2.Opacity = 1.0;
					useTop = true;

					DoubleAnimation a = new DoubleAnimation(1.0, 0.0, new Duration(new TimeSpan(0, 0, 2)));
					MyImage1.BeginAnimation(Image.OpacityProperty, a);
				}
			}
			else
				Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new DisplayImageDelegate(DisplayImage), imageName);
		}

	}
}
